package cn.runagain.demo.wechatminiappdemo.utils;

import org.apache.commons.codec.binary.Base64;

import javax.crypto.Cipher;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import java.security.AlgorithmParameters;
import java.util.Arrays;

/**
 * created by
 *
 * @author tuxianchao
 * @date 2018/7/3 上午12:21
 */
public class WechatDataDecrypt1 {


    public static void main(String[] args) {
        //        微信步数加密数据数据
        String encryptedData = "W9Ruco9RvBSIsX3eNecbRJ18khdpieU98kTD6HvInpxl1/LuVY8kfeTyadJIaVzsw7ZyE1pAVKO4FCHQY2ugMXn9DgIG8qzDQA7xjQF+sci5PQzVSSfq+Mo5xvlDap2bFw4Jp6OStYUef1H9rXDWEvExzKPYxf+rNgKYxZ3v6Pa6BbQeFnQn2+tHTHIrKBTZZ5UPXQp5lhRwi5KVZ5NS8PXtvGCA32rHAs3JuG7FB5sh/hYyVOGdkXbBrmwgzufRFUtoyIGACWGccG2MCy1BuY2xtPsxWZtAhpK9vX5gaEMXKgbsYV2RJeuMVRxObcWL2EY+gddwT4+akyvItOyZNVSORamgHyX7PwOQJtCSFL8Y16wVcwJ5uPzytb6dOXJN1y6EAYM15CA2azrCljvvXtDMXljvTAautj1CJyDMdFiFLrumoCBg/SmteCZiF6ELcxLmxiqv4jP3I96Ya6acLpQtUW2HaC2yfhPnQFDu8dRlam5mtz2f5XPNp6atL/3ThZhSOCRO5lraOv5+C4Bl0VYvnP897fmPNpymzkHUno88OzmG6vnGPA4x1D5oi/UnO+tuvKenlaMzcwlob37uFkpcZSmk32rulFCt1Aa/Yfw8DspaUO5pa9uP3szYmDB6kKKrIYVFj7V/rOleH7AHIlsyOyQlZ1GXvdimsPgn0XU7/KoreGrDgpedg5RQA/QG6t0P/X5uUPFZh0EUgzX1HEETX1X9KfARS8x/GmugVGZLP0gPc/8jnDSQ+FUotEsKNV4KjiCKawYvykdMEUqtRjSymtlNK6xQsX/JAj2Qfm+xqgsy6913EPREj+MFBrGepSpOCvXq/SG2ioBZIbQcMblq5MBAk0DJCR7ASApZAygqlB75WXm4eKBW1gVWQ8Ng1O3TAMvU7BjJNZrVFGFjNKY0dci1pcXk9S8z41sRBm9KPMJtdt0T1ulfn1EbQs/y00thmQ9IcDP33CO4FD13F7uXBDtryk31fqH7UKJEkzbP+Q1UQQmcrkRRUJRnpPKItQDHlQW1orYMZAqZHgLDw9zuKSQwu30ycxZvJIrV+kWXFvaXgQrel39z5IulR1Q4EC3okTsjDDfT+vmN/6Bkls2nBU+zt37zl056G2n8Q7R7Hvivf6pkEgWAK/QFrG5t5g6iT4PrcEQVENk8eSZ/TlHG8NB6lvP5xsfaFc+ZGEiqM2lHOnKOLZF6PuUx98NKeqKkerAtah5cAO72tfAqqST4d04YKDzLR7p8i4XVnatgmGcDmYyRUJhWzxq9FHyZ6li5Xgtkk2UrcmOKyYdIr0oaOaiI+IK1uIF3F3a0OGA9+2m4b1Hgdm5KpaQZmRGNcwinusVpyclbqcDvhj/jBJvaXIrgeJO7x9AAExQTQLbCxMg+RmYsFnP77858tkYMHTqEMZQsKxXheVvZ8jbMX345tRf4Zce154T6oCHHbxZMqsWNtChyv7Ko8AoiZWN20lJpS0u8PiCLUZmVOw1bI3Oddg9AxHGGbAT/Vcgud4JF8kxkz2WkWt3RlsvCpOOrwTwTSoHnVzLVnxUktMHLTMfl1tRI3M9gmEGH0ZH221D+S2QFDxga8tA1VJd+vCO1sgprAtfSqBWQkGwC+krPIkhGQn1A+DTJtSkoJNsi2yBP3254amYf2eVouZIs4sxG";
        String sessionKey = "fzmUYWl9GYBT4+cIfNZ/Eg==";
        String iv = "8rDOIx96pFTwGBfmYAcxaQ==";
        long start = System.currentTimeMillis();
        System.out.println(decrypt(sessionKey, encryptedData, iv));
        System.out.println("耗时:" + (System.currentTimeMillis() - start) + "ms");
    }

    public static String decrypt(String sessionKey, String encryptedData, String ivStr) {
        try {
            AlgorithmParameters params = AlgorithmParameters.getInstance("AES");
            params.init(new IvParameterSpec(Base64.decodeBase64(ivStr)));

            Cipher cipher = Cipher.getInstance("AES/CBC/NoPadding");
            cipher.init(Cipher.DECRYPT_MODE, new SecretKeySpec(Base64.decodeBase64(sessionKey), "AES"), params);

            return new String(decode(cipher.doFinal(Base64.decodeBase64(encryptedData))), StandardCharsets.UTF_8);
        } catch (Exception e) {
            throw new RuntimeException("AES解密失败", e);
        }
    }


    private static final Charset CHARSET = Charset.forName("utf-8");
    private static final int BLOCK_SIZE = 32;

    /**
     * 获得对明文进行补位填充的字节.
     *
     * @param count 需要进行填充补位操作的明文字节个数
     * @return 补齐用的字节数组
     */
    public static byte[] encode(int count) {
        // 计算需要填充的位数
        int amountToPad = BLOCK_SIZE - (count % BLOCK_SIZE);
        if (amountToPad == 0) {
            amountToPad = BLOCK_SIZE;
        }
        // 获得补位所用的字符
        char padChr = chr(amountToPad);
        String tmp = new String();
        for (int index = 0; index < amountToPad; index++) {
            tmp += padChr;
        }
        return tmp.getBytes(CHARSET);
    }

    /**
     * 删除解密后明文的补位字符
     *
     * @param decrypted 解密后的明文
     * @return 删除补位字符后的明文
     */
    public static byte[] decode(byte[] decrypted) {
        int pad = decrypted[decrypted.length - 1];
        if (pad < 1 || pad > 32) {
            pad = 0;
        }
        return Arrays.copyOfRange(decrypted, 0, decrypted.length - pad);
    }

    /**
     * 将数字转化成ASCII码对应的字符，用于对明文进行补码
     *
     * @param a 需要转化的数字
     * @return 转化得到的字符
     */
    public static char chr(int a) {
        byte target = (byte) (a & 0xFF);
        return (char) target;
    }
}
